package com.example.utility.crypto.dsa;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author 季舟
 * @Date 2024-12-19 14:42
 */
public class DSADemo {
    /**
     * 程序的主入口点
     * 本方法演示了如何生成密钥对，并使用私钥对数据进行签名，随后使用公钥验证签名
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        try {
            // 生成密钥对
            KeyPair keyPair = generateKeyPair();

            // 将公钥和私钥转换为Base64编码的字符串表示
            String publicKeyBase64= Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
            String privateKeyBase64=Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());

            // 打印公钥和私钥
            System.out.println("Public Key: " + publicKeyBase64);
            System.out.println("Private Key: " + privateKeyBase64);

            // 定义待签名的原始数据
            String originalData = "310765190001010018";

            // 使用私钥对原始数据进行签名
            String signData=signData(originalData,privateKeyBase64);

            // 打印签名数据
            System.out.println("Sign Data: "+signData);

            // 使用公钥验证签名
            boolean isVerified = verifySignature(originalData, signData, publicKeyBase64);

            // 打印签名验证结果
            System.out.println("签名验证结果: " + (isVerified ? "成功" : "失败")+", original data:"+originalData+", sign data:"+signData);

        }catch (Exception e){
            // 打印异常信息
            e.printStackTrace();
        }
    }

    /**
     * 生成DSA密钥对
     *
     * @return 包含公钥和私钥的KeyPair对象
     * @throws NoSuchAlgorithmException 如果指定的算法不存在
     */
    private static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        // 实例化密钥对生成器，指定算法为DSA
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
        // 初始化密钥对生成器，指定密钥长度为1024位
        keyGen.initialize(1024);
        // 生成并返回密钥对
        return keyGen.generateKeyPair();
    }


    /**
     * 使用私钥对原始数据进行签名
     *
     * @param originalData 待签名的原始数据
     * @param privateKeyBase64 Base64编码的私钥字符串
     * @return 签名后的Base64编码字符串
     * @throws Exception 如果签名过程中发生错误，则抛出异常
     */
    private static String signData(String originalData, String privateKeyBase64) throws Exception {
        // 将Base64编码的私钥字符串解码并生成PrivateKey对象
        PrivateKey privateKey= KeyFactory.getInstance("DSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64)));

        // 创建Signature对象，指定签名算法为SHA1withDSA
        Signature sig = Signature.getInstance("SHA1withDSA");

        // 初始化签名操作，使用私钥
        sig.initSign(privateKey);

        // 更新签名内容，即待签名的原始数据
        sig.update(originalData.getBytes());

        // 执行签名并获得签名结果的字节数组
        byte[] signDataBase64= sig.sign();

        // 将签名结果的字节数组转换为Base64编码字符串并返回
        return Base64.getEncoder().encodeToString(signDataBase64);
    }


    /**
     * 使用公钥验证数字签名
     *
     * @param originalData 待验证的原始数据
     * @param signDataBase64 Base64编码的签名数据
     * @param publicKeyBase64 Base64编码的公钥
     * @return 如果签名验证成功，则返回true；否则返回false
     * @throws Exception 如果验证过程中发生错误，则抛出异常
     */
    private static boolean verifySignature(String originalData, String signDataBase64, String publicKeyBase64) throws Exception {
        // 使用DSA算法生成PublicKey对象
        PublicKey publicKey= KeyFactory.getInstance("DSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64)));

        // 将Base64编码的签名数据转换为字节数组
        byte[] signData = Base64.getDecoder().decode(signDataBase64);

        // 创建Signature对象，用于验证签名
        Signature sig = Signature.getInstance("SHA1withDSA");

        // 初始化验证操作，使用公钥
        sig.initVerify(publicKey);

        // 更新签名对象，使用原始数据的字节
        sig.update(originalData.getBytes());

        // 验证签名，并返回验证结果
        return sig.verify(signData);
    }
}
